<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>澜音 - 桌面歌词</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        user-select: none;
        box-sizing: border-box;
        -webkit-user-drag: none;
      }

      :root {
        --font-size: 30;
        --main-color: #73bcfc;
        --shadow-color: rgba(255, 255, 255, 0.5);
        --next-color: rgba(255, 255, 255, 0.68);
      }

      body {
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 100%;
        height: 100%;
        padding: 12px;
        cursor: pointer;
        color: var(--main-color);
        overflow: hidden;
        transition: opacity 0.3s;

        &::after {
          content: '';
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          border-radius: 16px;
          background-color: rgba(0, 0, 0, 0.8);
          backdrop-filter: blur(10px);
          z-index: 0;
          opacity: 0;
          cursor: move;
          transition: opacity 0.3s;
        }

        &:hover {
          &::after {
            opacity: 1;
          }

          header {
            .meta {
              opacity: 0;
            }

            .tools {
              opacity: 1;
            }
          }
        }

        &.lock-lyric {
          cursor: none;
          /* 鼠标穿透 */
          pointer-events: none;

          * {
            pointer-events: none;
          }

          &::after {
            opacity: 0;
          }

          &:hover {
            opacity: 0;
          }

          header {
            .meta {
              opacity: 1;
            }

            .tools {
              opacity: 0;
            }
          }
        }
      }

      header {
        display: flex;
        align-items: center;
        justify-content: center;
        position: relative;
        z-index: 1;

        .meta {
          display: flex;
          flex-direction: column;
          align-items: center;
          font-size: 14px;
          opacity: 0.9;
          transition: opacity 0.3s;
        }

        .tools {
          display: flex;
          align-items: center;
          justify-content: center;
          position: absolute;
          opacity: 0;
          transition: opacity 0.3s;
          gap: 8px;

          .item {
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 6px;
            border-radius: 8px;
            cursor: pointer;
            transition:
              transform 0.3s,
              background-color 0.3s;

            &.hidden {
              display: none;
            }

            &:hover {
              background-color: rgba(0, 0, 0, 0.4);
            }

            &:active {
              transform: scale(0.95);
            }

            svg {
              width: 24px;
              height: 24px;
            }
          }
        }

        #song-artist {
          margin-top: 4px;
          font-size: 12px;
          opacity: 0.8;
        }
      }

      main {
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 0 12px;
        margin: 12px;
        z-index: 1;
        max-width: 100%;
        pointer-events: auto;
        width: 100%;

        #lyric-text {
          font-size: calc(var(--font-size) * 1px);
          font-weight: bold;
        }

        #lyric-tran {
          font-size: calc(var(--font-size) * 1px - 5px);
          margin-top: 8px;
          opacity: 0.6;
        }
      }

      span {
        padding: 0 4px;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        text-shadow: 0 0 4px var(--shadow-color);
        transition: opacity 0.3s;
        /* animation: 15s wordsLoop linear infinite normal; */
      }

      @keyframes wordsLoop {
        0% {
          transform: translateX(0px);
        }

        100% {
          transform: translateX(-100%);
        }
      }

      /* 双行交错歌词布局 */
      .lines-root {
        position: relative;
        width: 100%;
        display: flex;
        flex-direction: column;
        gap: 10px;
        align-items: stretch;
      }
      .line {
        display: flex;
        flex-direction: column;
        width: 100%;
        transition: transform 0.35s ease, opacity 0.35s ease;
        will-change: transform, opacity;
      }
      .line *{
                transition:
          transform 0.35s ease,
          opacity 0.35s ease;
        will-change: transform, opacity;
        text-shadow: 0 0 4px var(--shadow-color);

      }
      .line .text {
        font-size: calc(var(--font-size) * 1px);
        font-weight: 700;
      }
      .line .tran {
        font-size: calc(var(--font-size) * 1px - 5px);
        opacity: 0.6;
        margin-top: 6px;
      }
      .line.left {
        align-items: flex-start;
        text-align: left;
      }
      .line.right {
        align-items: flex-end;
        text-align: right;
      }

      /* 当前句 vs 下一句 颜色区分 */
      .line.current .text {
        color: var(--main-color);
        opacity: 1;
      }
      .line.current .tran {
        opacity: 0.8;
      }
      .line.upnext .text {
        color: var(--next-color);
        opacity: 0.65;
      }
      .line.upnext .tran {
        opacity: 0.45;
      }

      /* 进入动画：使用关键帧，避免过渡时序问题 */
      @keyframes lyricEnter {
        from { opacity: 0; transform: translateY(8px); }
        to   { opacity: 1; transform: translateY(0); }
      }
      /* 备用：如果需要离场可再启用 */
      @keyframes lyricLeave {
        from { opacity: 1; transform: translateY(0); }
        to   { opacity: 0; transform: translateY(-8px); }
      }
    </style>
  </head>

  <body>
    <header>
      <div class="meta">
        <span id="song-name">CeruMusic（澜音）</span>
        <span id="song-artist">未知艺术家</span>
      </div>
      <div class="tools" id="tools">
        <div id="show-app" class="item" title="打开应用">
          <svg
            width="1200"
            height="1200"
            viewBox="0 0 1200 1200"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
          >
            <rect width="1200" height="1200" rx="379" fill="white" />
            <path
              d="M957.362 204.197C728.535 260.695 763.039 192.264 634.41 175.368C451.817 151.501 504.125 315.925 504.125 315.925L630.545 673.497C591.211 654.805 544.287 643.928 494.188 643.928C353.275 643.928 239 729.467 239 834.964C239 940.567 353.137 1026 494.188 1026C635.1 1026 749.375 940.461 749.375 834.964C749.375 832.218 749.237 829.473 749.099 826.727C749.513 825.988 749.789 825.143 750.065 824.087C757.932 789.449 634.272 348.345 634.272 348.345C634.272 348.345 764.971 401.886 860.89 351.936C971.163 294.699 964.953 202.402 957.362 204.197Z"
              fill="url(#paint0_linear_4_16)"
              stroke="#29293A"
              stroke-opacity="0.23"
            />
            <defs>
              <linearGradient
                id="paint0_linear_4_16"
                x1="678.412"
                y1="-1151.29"
                x2="796.511"
                y2="832.071"
                gradientUnits="userSpaceOnUse"
              >
                <stop offset="0.572115" stop-color="#B8F1ED" />
                <stop offset="0.9999" stop-color="#B8F1CC" />
              </linearGradient>
            </defs>
          </svg>
        </div>
        <div id="font-size-reduce" class="item" title="缩小字体">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M10.5 7h-2L3 21h2.2l1.1-3h6.2l1.1 3H16zm-3.4 9l2.4-6.3l2.4 6.3zM22 7h-8V5h8z"
            />
          </svg>
        </div>
        <div id="font-size-add" class="item" title="放大字体">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M8.5 7h2L16 21h-2.4l-1.1-3H6.3l-1.1 3H3zm-1.4 9h4.8L9.5 9.7zM22 5v2h-3v3h-2V7h-3V5h3V2h2v3z"
            />
          </svg>
        </div>
        <div id="play-prev" class="item" title="上一首">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M7 6c.55 0 1 .45 1 1v10c0 .55-.45 1-1 1s-1-.45-1-1V7c0-.55.45-1 1-1m3.66 6.82l5.77 4.07c.66.47 1.58-.01 1.58-.82V7.93c0-.81-.91-1.28-1.58-.82l-5.77 4.07a1 1 0 0 0 0 1.64"
            />
          </svg>
        </div>
        <!-- 播放暂停 -->
        <div id="pause" class="item hidden" title="暂停">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M8 19c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2v10c0 1.1.9 2 2 2m6-12v10c0 1.1.9 2 2 2s2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2"
            />
          </svg>
        </div>
        <div id="play" class="item" title="播放">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18a1 1 0 0 0 0-1.69L9.54 5.98A.998.998 0 0 0 8 6.82"
            />
          </svg>
        </div>
        <div id="play-next" class="item" title="下一首">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="m7.58 16.89l5.77-4.07c.56-.4.56-1.24 0-1.63L7.58 7.11C6.91 6.65 6 7.12 6 7.93v8.14c0 .81.91 1.28 1.58.82M16 7v10c0 .55.45 1 1 1s1-.45 1-1V7c0-.55-.45-1-1-1s-1 .45-1 1"
            />
          </svg>
        </div>
        <!-- 锁定 -->
        <div id="lock-lyric" class="item" title="锁定/解锁">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2M9 6c0-1.66 1.34-3 3-3s3 1.34 3 3v2H9zm9 14H6V10h12zm-6-3c1.1 0 2-.9 2-2s-.9-2-2-2s-2 .9-2 2s.9 2 2 2"
            />
          </svg>
        </div>
        <!-- 关闭 -->
        <div id="close-lyric" class="item" title="关闭">
          <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
            <path
              fill="currentColor"
              d="M13.46 12L19 17.54V19h-1.46L12 13.46L6.46 19H5v-1.46L10.54 12L5 6.46V5h1.46L12 10.54L17.54 5H19v1.46z"
            />
          </svg>
        </div>
      </div>
    </header>
    <main id="lyric-content">
      <span id="lyric-text" style="display: none">该歌曲暂无歌词</span>
      <span id="lyric-tran" style="display: none"></span>
      <div id="lines-root" class="lines-root">
        <div class="line line-a left">
          <div class="text"></div>
          <div class="tran"></div>
        </div>
        <div class="line line-b right">
          <div class="text"></div>
          <div class="tran"></div>
        </div>
      </div>
    </main>
    <script>
      class LyricsWindow {
        constructor() {
          // 获取元素
          this.songNameDom = document.getElementById('song-name')
          this.songArtistDom = document.getElementById('song-artist')
          this.lyricContentDom = document.getElementById('lyric-content')
          this.lyricTextDom = document.getElementById('lyric-text')
          this.lyricTranDom = document.getElementById('lyric-tran')
          this.pauseDom = document.getElementById('pause')
          this.playDom = document.getElementById('play')
          // 窗口位置
          this.isDragging = false
          this.startX = 0
          this.startY = 0
          this.startWinX = 0
          this.startWinY = 0
          this.winWidth = 0
          this.winHeight = 0
          // 临时变量
          // this.lyricIndex = -1;
          // 每首歌起始基准索引，用于保证第一句总在左侧
          this._baseIndex = null
          // 上一索引与延迟更新队列（仅延迟“上一行->下一行”的替换）
          this._lastIndex = -1
          this._pendingUpnext = null // { wrapEl, textEl, tranEl, data }
          this._lastLyricPayload = { lyric: [] }
          // 初始化
          this.restoreOptions()
          this.menuClick()
          this.setupIPCListeners()
          this.setupWindowDragListeners()
          this.setupMutationObserver()
        }
        // 准备态渲染：展示第 1、2 句左右铺开，不标记 current/upnext
        renderPrepare() {
          const payload = this._lastLyricPayload || { lyric: [] }
          const lines = payload.lyric || []
          if (!Array.isArray(lines) || lines.length === 0) return
          const first = lines[0] || { content: '', tran: '' }
          const second = lines[1] || { content: '', tran: '' }
          const root = document.getElementById('lines-root')
          const lineA = root.querySelector('.line-a')
          const lineB = root.querySelector('.line-b')
          const aText = lineA.querySelector('.text')
          const aTran = lineA.querySelector('.tran')
          const bText = lineB.querySelector('.text')
          const bTran = lineB.querySelector('.tran')
          lineA.classList.remove('current', 'upnext')
          lineB.classList.remove('current', 'upnext')
          const updateSide = (wrapEl, textEl, tranEl, data) => {
            const newText = data?.content || ''
            const newTran = data?.tran || ''
            if (textEl.textContent !== newText || tranEl.textContent !== newTran) {
              textEl.textContent = newText
              tranEl.textContent = newTran
              wrapEl.style.animation = 'none'
              void wrapEl.offsetWidth
              wrapEl.style.animation = 'lyricEnter 0.35s ease'
            }
          }
          updateSide(lineA, aText, aTran, first)
          updateSide(lineB, bText, bTran, second)
        }

        // 基于当前行索引的“AB 交错 + 预显下一句”规则：
        // 当前 index 偶数 -> 左=当前句(index)，右=下一句(index+1)
        // 当前 index 奇数 -> 左=下一句(index+1)，右=当前句(index)
        renderByIndex(index) {
          const payload = this._lastLyricPayload || { lyric: [] }
          const lines = payload.lyric || []
          if (!Array.isArray(lines) || lines.length === 0) return
          if (typeof index !== 'number' || index < 0 || index >= lines.length) return

          // 锁定基准：确保每首歌的第一句渲染在左侧
          if (this._baseIndex === null) this._baseIndex = index

          const cur = lines[index] || { content: '纯音乐，请欣赏', tran: '' }
          const next = lines[index + 1] || { content: '', tran: '' }

          const root = document.getElementById('lines-root')
          const lineA = root.querySelector('.line-a')
          const lineB = root.querySelector('.line-b')
          const aText = lineA.querySelector('.text')
          const aTran = lineA.querySelector('.tran')
          const bText = lineB.querySelector('.text')
          const bTran = lineB.querySelector('.tran')

          const even = (index - this._baseIndex) % 2 === 0

          // 标记当前句与下一句以应用不同颜色样式（立即切换高亮，不等 30%）
          lineA.classList.remove('current', 'upnext')
          lineB.classList.remove('current', 'upnext')
          let currentWrap, currentText, currentTran, upnextWrap, upnextText, upnextTran
          if (even) {
            // 左：当前；右：下一
            lineA.classList.add('current')
            lineB.classList.add('upnext')
            currentWrap = lineA
            currentText = aText
            currentTran = aTran
            upnextWrap = lineB
            upnextText = bText
            upnextTran = bTran
          } else {
            // 左：下一；右：当前
            lineA.classList.add('upnext')
            lineB.classList.add('current')
            currentWrap = lineB
            currentText = bText
            currentTran = bTran
            upnextWrap = lineA
            upnextText = aText
            upnextTran = aTran
          }

          const updateSide = (wrapEl, textEl, tranEl, data) => {
            const newText = data?.content || ''
            const newTran = data?.tran || ''
            const oldText = textEl.textContent || ''
            const oldTran = tranEl.textContent || ''
            if (newText === oldText && newTran === oldTran) return
            textEl.textContent = newText
            tranEl.textContent = newTran
            wrapEl.style.animation = 'none'
            void wrapEl.offsetWidth
            wrapEl.style.animation = 'lyricEnter 0.35s ease'
          }

          // 1) 立即更新“当前句”内容，保证开始朗读就高亮且正确
          updateSide(currentWrap, currentText, currentTran, cur)

          // 2) 对“上一行 -> 下一行”的替换延迟到 30% 进度
          const desiredUpText = next?.content || ''
          const desiredUpTran = next?.tran || ''
          const upOldText = upnextText.textContent || ''
          const upOldTran = upnextTran.textContent || ''

          // 若 upnext 目前已是下一句，则无需延迟
          if (desiredUpText === upOldText && desiredUpTran === upOldTran) {
            this._pendingUpnext = null
          } else {
            // 仅记录待更新，不立刻替换
            this._pendingUpnext = {
              index,
              wrapEl: upnextWrap,
              textEl: upnextText,
              tranEl: upnextTran,
              data: next
            }
          }
        }
        // 获取配置
        async restoreOptions() {
          try {
            const defaultOptions = await window.electron.ipcRenderer.invoke(
              'get-desktop-lyric-option'
            )
            if (defaultOptions) this.changeOptions(defaultOptions)
            return defaultOptions
          } catch (error) {
            console.error('Failed to restore options:', error)
          }
        }
        // 修改配置
        changeOptions(options, callback = true) {
          if (!options) return
          const { fontSize, mainColor, shadowColor } = options
          const root = document.documentElement
          root.style.setProperty('--font-size', fontSize)
          root.style.setProperty('--main-color', mainColor)
          root.style.setProperty('--shadow-color', shadowColor)
          // 基于主色生成灰度化的 next 颜色（使用 color-mix 提升兼容/观感）
          try {
            const next = `color-mix(in srgb, ${mainColor} 35%, white 65%)`
            root.style.setProperty('--next-color', next)
          } catch (e) {
            // 退化：若不支持 color-mix，则使用固定透明度的主色
            root.style.setProperty('--next-color', mainColor)
          }
          if (callback) window.electron.ipcRenderer.send('set-desktop-lyric-option', options)
        }
        // 菜单点击事件
        menuClick() {
          const toolsDom = document.getElementById('tools')
          if (!toolsDom) return
          // 菜单项点击
          toolsDom.addEventListener('click', async (event) => {
            const target = event.target.closest('div')
            if (!target) return
            console.log(target)
            const id = target.id
            if (!id) return
            // 获取配置
            const options = await this.restoreOptions()
            switch (id) {
              case 'show-app': {
                window.electron.ipcRenderer.send('win-show')
                break
              }
              case 'font-size-add': {
                let fontSize = options.fontSize
                if (fontSize < 60) {
                  fontSize++
                  this.changeOptions({ ...options, fontSize })
                }
                break
              }
              case 'font-size-reduce': {
                let fontSize = options.fontSize
                if (fontSize > 10) {
                  fontSize--
                  this.changeOptions({ ...options, fontSize })
                }
                break
              }
              case 'play': {
                window.electron.ipcRenderer.send('send-main-event', 'play')
                break
              }
              case 'pause': {
                window.electron.ipcRenderer.send('send-main-event', 'pause')
                break
              }
              case 'play-prev': {
                window.electron.ipcRenderer.send('send-main-event', 'playPrev')
                break
              }
              case 'play-next': {
                window.electron.ipcRenderer.send('send-main-event', 'playNext')
                break
              }
              case 'close-lyric': {
                window.electron.ipcRenderer.send('closeDesktopLyric')
                break
              }
              case 'lock-lyric': {
                const locked = !document.body.classList.contains('lock-lyric')
                document.body.classList.toggle('lock-lyric', locked)
                window.electron.ipcRenderer.send('toogleDesktopLyricLock', locked)
                break
              }
              default:
                break
            }
          })
        }
        // 监听 IPC 事件
        setupIPCListeners() {
          window.electron.ipcRenderer.on('play-song-change', (_, title) => {
            if (!title) return
            const [songName, songArtist] = title.split(' - ')
            this.songNameDom.innerHTML = songName
            this.songArtistDom.innerHTML = songArtist
            // 每首歌切换时重置基准索引，确保首句在左侧
            this._baseIndex = null
            this.updateLyrics(title)
          })

          window.electron.ipcRenderer.on('play-lyric-change', (_, lyricData) => {
            if (!lyricData) return
            this.parsedLyricsData(lyricData)
          })

          // 接收当前行索引（若主进程/渲染端已推送 index）并按奇偶切换 A/B 行，避免“右侧唱完才换左侧”的滞后问题
          window.electron.ipcRenderer.on('play-lyric-index', (_, index) => {
            this._lastIndex = this._lastIndex ?? -1
            if (typeof index !== 'number' || index === this._lastIndex) return

            // 准备态：index === -1，先展示第 1、2 句左右铺开（不打标 current/upnext）
            if (index === -1) {
              this._baseIndex = null
              this._lastIndex = index
              this.renderPrepare()
              return
            }

            // 第一次收到该首歌的有效 index，锁定基准，保证奇偶性从 index 开始算起时首句落在左侧
            if (this._baseIndex === null) this._baseIndex = index
            this._lastIndex = index
            this.renderByIndex(index)
          })

          window.electron.ipcRenderer.on('play-status-change', (_, status) => {
            this.playDom.classList.toggle('hidden', status)
            this.pauseDom.classList.toggle('hidden', !status)
          })

          // 进度事件：用于 30% 后再替换上一侧为“下一句”
          window.electron.ipcRenderer.on('play-lyric-progress', (_, payload) => {
            try {
              const { index, progress } = payload || {}
              if (!this._pendingUpnext) return
              // 仅当仍在同一行朗读时触发
              if (typeof index !== 'number' || index !== this._pendingUpnext.index) return
              if (typeof progress !== 'number' || progress < 0.3) return
              const { wrapEl, textEl, tranEl, data } = this._pendingUpnext
              const newText = data?.content || ''
              const newTran = data?.tran || ''
              if (textEl.textContent === newText && tranEl.textContent === newTran) {
                this._pendingUpnext = null
                return
              }
              // 执行替换与入场动画
              textEl.textContent = newText
              tranEl.textContent = newTran
              wrapEl.style.animation = 'none'
              void wrapEl.offsetWidth
              wrapEl.style.animation = 'lyricEnter 0.35s ease'
              this._pendingUpnext = null
            } catch {}
          })

          // 配置变化
          window.electron.ipcRenderer.on('desktop-lyric-option-change', (_, options) => {
            this.changeOptions(options, false)
          })

          // 歌词锁定（仅更新样式，不再回传，避免事件循环）
          window.electron.ipcRenderer.on('toogleDesktopLyricLock', (_, lock) => {
            document.body.classList.toggle('lock-lyric', lock)
          })
        }
        // 解析歌词
        parsedLyricsData(lyricData) {
          if (!this.lyricContentDom || !this.lyricTextDom) return
          const { index, lyric } = lyricData
          // 缓存全集合，等待 index 推送来决定显示侧（奇偶）
          this._lastLyricPayload = { lyric }

          if (!lyric || lyric.length === 0) {
            this.updateLyrics()
            return
          }

          // 如果带 index，则立即按规则渲染；否则等待 play-lyric-index（桥接侧也会周期推 index）
          if (typeof index === 'number' && index >= 0 && index < lyric.length) {
            this.renderByIndex(index)
          }
        }
        // 拖拽窗口
        setupWindowDragListeners() {
          document.addEventListener('mousedown', this.startDrag.bind(this))
          document.addEventListener('mousemove', this.dragWindow.bind(this))
          document.addEventListener('mouseup', this.endDrag.bind(this))
        }
        // 开始拖拽
        async startDrag(event) {
          this.isDragging = true
          const { screenX, screenY } = event
          const {
            x: winX,
            y: winY,
            width,
            height
          } = await window.electron.ipcRenderer.invoke('get-window-bounds')
          this.startX = screenX
          this.startY = screenY
          this.startWinX = winX
          this.startWinY = winY
          this.winWidth = width
          this.winHeight = height
        }
        // 拖拽
        async dragWindow(event) {
          if (!this.isDragging) return
          const { screenX, screenY } = event
          let newWinX = this.startWinX + (screenX - this.startX)
          let newWinY = this.startWinY + (screenY - this.startY)
          const { width: screenWidth, height: screenHeight } =
            await window.electron.ipcRenderer.invoke('get-screen-size')
          newWinX = Math.max(0, Math.min(screenWidth - this.winWidth, newWinX))
          newWinY = Math.max(0, Math.min(screenHeight - this.winHeight, newWinY))
          window.electron.ipcRenderer.send(
            'move-window',
            newWinX,
            newWinY,
            this.winWidth,
            this.winHeight
          )
        }
        // 结束拖拽
        endDrag() {
          this.isDragging = false
        }
        // 更新高度
        updateWindowHeight() {
          const bodyHeight = document.body.scrollHeight
          window.electron.ipcRenderer.send('update-window-height', bodyHeight)
        }
        // 动态监听高度
        setupMutationObserver() {
          const observer = new MutationObserver(this.updateWindowHeight.bind(this))
          observer.observe(document.body, { childList: true, subtree: true, attributes: true })
          this.updateWindowHeight()
        }
      }

      new LyricsWindow()
    </script>
  </body>
</html>
